package model;

import java.util.HashMap;
import java.util.Map;

/**
 * main.Game figures. Each figure has four distinctive features:
 * <p/>
 * squared - round
 * black - white
 * big - small
 * solid - pierced
 * <p/>
 * Each figure has code. For example
 * squared white small pierced figure has code 1100
 *
 * @author Alex Vikharev alex.vikharev@gmail.com
 *         created 25.01.12
 */
public enum Figure {
    SQUARED_BLACK_BIG_SOLID(0b0000),
    SQUARED_BLACK_BIG_PIERCED(0b0001),
    SQUARED_BLACK_SMALL_SOLID(0b0010),
    SQUARED_BLACK_SMALL_PIERCED(0b0011),

    SQUARED_WHITE_BIG_SOLID(0b0100),
    SQUARED_WHITE_BIG_PIERCED(0b0101),
    SQUARED_WHITE_SMALL_SOLID(0b0110),
    SQUARED_WHITE_SMALL_PIERCED(0b0111),

    ROUND_BLACK_BIG_SOLID(0b1000),
    ROUND_BLACK_BIG_PIERCED(0b1001),
    ROUND_BLACK_SMALL_SOLID(0b1010),
    ROUND_BLACK_SMALL_PIERCED(0b1011),

    ROUND_WHITE_BIG_SOLID(0b1100),
    ROUND_WHITE_BIG_PIERCED(0b1101),
    ROUND_WHITE_SMALL_SOLID(0b1110),
    ROUND_WHITE_SMALL_PIERCED(0b1111),;

    public final int code;
    public final double[] bits;
    private static final Map<Integer, Figure> codeToFigure = new HashMap<>();

    static {
        for (Figure figure : Figure.values()) {
            codeToFigure.put(figure.code, figure);
        }
    }

    Figure(int code) {
        this.code = code;
        bits = new double[4];
        bits[0] = Math.signum(code & 0b1);
        bits[1] = Math.signum(code & 0b10);
        bits[2] = Math.signum(code & 0b100);
        bits[3] = Math.signum(code & 0b1000);
    }

    public static Figure byCode(int code) {
        if (code < 0 || code > 15) {
            throw new IllegalArgumentException("Wrong code");
        }
        return codeToFigure.get(code);
    }

    public Figure invert() {
        return byCode(~this.code & 0b1111);
    }

    public Figure xor(int xor) {
        return byCode(this.code ^ xor);
    }

    public Figure permute(int[] permutation) {
        int result = 0;
        for (int i = 0; i < 4; i++) {
            int bit = (this.code & (1 << i)) == 0 ? 0 : 1;
            bit <<= permutation[i];
            result |= bit;
        }
        return byCode(result);
    }

    public String toBinary() {
        return String.format("%4s", Integer.toBinaryString(code)).replace(' ', '0');
    }

}
